package com.example.seckill.service.impl;

import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.seckill.controller.co.OrderCO;
import com.example.seckill.domain.OrderDO;
import com.example.seckill.domain.PromoDO;
import com.example.seckill.domain.SequenceInfo;
import com.example.seckill.error.BusinessException;
import com.example.seckill.error.CommonErrorEnum;
import com.example.seckill.mappstruct.OrderMap;
import com.example.seckill.service.*;
import com.example.seckill.mapper.OrderInfoMapper;
import com.example.seckill.service.model.ItemModel;
import com.example.seckill.service.model.OrderModel;
import com.example.seckill.service.model.PromoStatusEnum;
import com.example.seckill.service.model.UserModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Objects;

/**
 *
 */
@Service
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderDO> implements OrderInfoService {
    @Autowired
    private UserInfoService userInfoService;
    @Autowired
    private ItemService itemService;
    @Autowired
    private OrderInfoService orderInfoService;
    @Autowired
    private SequenceInfoService sequenceInfoService;
    @Autowired
    private PromoService promoService;

    /**
     *
     * 改造前 10个sql
     * 问题:
     * 1.验证依赖数据库,查询
     * 2.库存行锁
     * 3.后置处理逻辑
     */
    @Override
    @Transactional
    public OrderModel createOrder(Integer userId, OrderCO orderCO) {
        Integer itemId = orderCO.getItemId();
        Integer amount = orderCO.getAmount();
        //商品数量校验
        if (amount <= 0 || amount > 99) {
            throw new BusinessException(CommonErrorEnum.PARAMETER_VALIDATION_ERROR, "商品数量不符合要求");
        }
        //用户查询 校验 2个sql
        UserModel userModel = userInfoService.getUserById(userId);
        if (userModel == null) {
            throw new BusinessException(CommonErrorEnum.PARAMETER_VALIDATION_ERROR, "用户信息不存在");
        }
        //商品查询校验,查出促销信息 3个sql
        ItemModel itemModel = itemService.findById(itemId);//带促销信息
        if (itemModel == null) {
            throw new BusinessException(CommonErrorEnum.PARAMETER_VALIDATION_ERROR, "商品信息不存在");
        }

        //校验促销信息
        if (orderCO.getPromoId() != null) {
            //校验促销信息
            Assert.state(Objects.equals(itemModel.getPromoModel().getPromoId(), orderCO.getPromoId()));
            Assert.state(itemModel.getPromoStatusEnum()==PromoStatusEnum.IN_PROMO);
        }
        //创建订单前先减库存 1个sql update 库存是行锁,是一个瓶颈
        boolean result = itemService.decreaseStock(itemId, amount);
        if (!result) {
            throw new BusinessException(CommonErrorEnum.STOCK_NOT_ENOUGH);
        }
        //生成订单号,生成订单 2个sql+1个sql
        String orderNo = orderInfoService.generateOrderNo();//订单号
        OrderModel orderModel = new OrderModel();
        orderModel.setId(orderNo);
        orderModel.setItemId(itemId);
        orderModel.setUserId(userId);
        orderModel.setAmount(amount);
        orderModel.setPromoId(orderCO.getPromoId());
        if (itemModel.getPromoStatusEnum() == PromoStatusEnum.IN_PROMO) {
            orderModel.setItemPrice(itemModel.getPromoModel().getPromoPrice());
            orderModel.setOrderPrice(itemModel.getPromoModel().getPromoPrice().multiply(new BigDecimal(amount)));
        }else {
            orderModel.setItemPrice(itemModel.getPrice());
            orderModel.setOrderPrice(itemModel.getPrice().multiply(new BigDecimal(amount)));
        }
        OrderDO orderDO = OrderMap.INSTANCE.convertFromModel(orderModel);
        this.baseMapper.insert(orderDO);
        //商品销量+1 1个sql
        itemService.increaseSales(itemId, amount);
        return orderModel;
    }

    //要求订单号全局唯一性的特性,所以新开一个事务!!独立的,对应的currentValue必须加完!
    //16=8年月日+6自增+2分库分表
    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public String generateOrderNo() {
        StringBuilder sb = new StringBuilder();
        sb.append(DateTimeFormatter.BASIC_ISO_DATE.format(LocalDate.now()));
        SequenceInfo sequenceInfo = sequenceInfoService.getOne(new QueryWrapper<SequenceInfo>().lambda().eq(SequenceInfo::getColumnName, "order_info"));
        Integer result = sequenceInfo.getCurrentValue() + sequenceInfo.getStep();
        if (result > sequenceInfo.getMaxValue()) {
            result = result - sequenceInfo.getMaxValue();
        }
        sequenceInfo.setCurrentValue(result);
        sequenceInfoService.update(sequenceInfo, new QueryWrapper<SequenceInfo>().lambda().eq(SequenceInfo::getColumnName, "order_info"));
        for (int i = 0; i < 6 - getLengthOfInterger(result); i++) {
            sb.append("0");
        }
        sb.append(result);
        //分库分表
        sb.append("01");
        return sb.toString();
    }

    private static Integer getLengthOfInterger(Integer num) {
        final int[] sizeTable = {9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999, Integer.MAX_VALUE};
        // Requires positive x
        for (int i = 0; ; i++)
            if (num <= sizeTable[i])
                return i + 1;
    }


}




